#include "backdrop_number_fx.h"
#include "math/plane.h"
#include "num/rand.h"
#include "util/timer.h"				// log
#include "util/log.h"				// log
#include "util/common_macros.h"		// macros
#include "util/mmgr.h"		    
#include <math.h>
using namespace backdrop;

BackdropNumberFXEntry::BackdropNumberFXEntry() :
	m_pBackgdropSFXSet(NULL),
	m_Number(0),
	m_DigitC(0),
	m_CurrentTime(-1), 
	m_MaxTime(-1),
	m_Color(0xFFFFFFFF)
{
}

BackdropNumberFXEntry::~BackdropNumberFXEntry()
{
}

void	BackdropNumberFXEntry::Reset(int Number, int DigitC, const math::Vec2& From, const math::Vec2& To, float Time)
{
	m_From = From;
	m_To = To;
	m_Pos = m_From;
	m_CurrentTime = m_MaxTime = Time;
	//m_Color = 0xFFFFFFFF;

	m_Number = Number;//abs(Number);
	m_DigitC = DigitC;
	OnCreation();

	m_Speed = 1.0;
	m_Offset = 0.0;
	m_Amplitude = 0.0f;

}

void	BackdropNumberFXEntry::SetupWave(float Speed, float Offset, float Amplitude)
{
	m_Speed = Speed;
	m_Offset = Offset;
	m_Amplitude = Amplitude;
}


bool	BackdropNumberFXEntry::Tick(float dt)
{
	m_CurrentTime-=dt;

	float	Fraction = GetFraction();
	float	Offset = sinf(m_Offset + (Fraction*m_Speed)) 
					* m_Amplitude * sinf(Fraction*3.14f);
	m_Pos = m_From + math::Vec2(0, Offset) + ( (m_To-m_From) * Fraction);


//	m_Pos = m_From + ((m_To-m_From)*GetFraction());
	bool	IsComplete = !IsValid();	
	if (IsComplete)
	{
		OnArrival();
	}
	return IsComplete;
}

void		BackdropNumberFXEntry::OnArrival()
{
	if (m_pBackgdropSFXSet && m_pBackgdropSFXSet->GetParent()) 
		m_pBackgdropSFXSet->GetParent()->AddScore(m_Number);
}


BackdropNumberFXSet::BackdropNumberFXSet(camera::AbstractCamera* pCam, BackdropSFX* pParent) :
	BackgdropSFXSet(pCam, pParent),
	m_MaxNumberC(0),
	m_ActiveNumberC(0),
	m_NumberI(0),
	m_NumberA(NULL),
	m_Time(1.0f),
	m_MoveTime(1,1),
	m_MoveSpeed(1,1),
	m_MoveAmplitude(1,1)
{
	m_BufferA = new Graphics::Vertex2D[BUFFER_SIZE];
}

BackdropNumberFXSet::~BackdropNumberFXSet()
{
	UTIL_SAFE_DELETEA(m_NumberA);
	UTIL_SAFE_DELETEA(m_BufferA);
}



void	BackdropNumberFXSet::FlushBuffer()
{
	if (m_VertexC == 0) return;

	GetGraphics()->DrawVertex2D(m_BufferA, m_VertexC);
	m_VertexC = 0;
}


void	BackdropNumberFXSet::Render()
{
	if (m_NumberA && m_ActiveNumberC > 0)
	{
		m_VertexC = 0;
		float TimeStamp  = TIMER().Time();
		m_Number.SetImage();
		for (unsigned int i=0; i<(unsigned int)m_MaxNumberC; i++)
		{		
			if (m_NumberA[i].IsValid())
			{
				if (m_VertexC + (m_NumberA[i].GetDigitC() * 6) >= BUFFER_SIZE)
				{
					// ensure that we track the digits being written and don't overflow the buffer
					FlushBuffer();
				}
			
			float	Fraction = m_NumberA[i].GetFraction();
			float	SizeFactor = 0.5f + sinf(Fraction*3.14f);

			m_VertexC += m_Number.FillScaledBuffer(
				m_NumberA[i].GetNumber(),	// digit
				m_NumberA[i].GetPos() ,	// position
				true,					// add commas
				&m_BufferA[m_VertexC], BUFFER_SIZE-m_VertexC, m_NumberA[i].GetColor(),
				m_Number.GetSize() * SizeFactor);
			}
		}
		FlushBuffer();
	}
}

void	BackdropNumberFXSet::Tick(float dt)
{
	if (m_NumberA && m_ActiveNumberC > 0)
	{
		for (int i=0; i<m_MaxNumberC; i++)
		{
			if (m_NumberA[i].IsValid())
			{
				if (m_NumberA[i].Tick(dt))	// expired
					m_ActiveNumberC--;
			}
		}
	}
}

void	BackdropNumberFXSet::Load(const std::string& File, int MaxNumber)
{
	UTIL_SAFE_DELETEA(m_NumberA);
	m_Number.Load(File);
	CreateSet(MaxNumber);
	m_ActiveNumberC = 0;
	m_NumberI = 0;
}

void	BackdropNumberFXSet::CreateSet(int Max)
{
	UTIL_SAFE_DELETEA(m_NumberA);
	m_MaxNumberC = Max;
	m_NumberA = new BackdropNumberFXEntry[m_MaxNumberC];
	for (int i=0; i<m_MaxNumberC; i++)
		m_NumberA[i].SetBackgdropSFXSet(this);
}


void	BackdropNumberFXSet::AddNumber(int Number, const math::Vec2& From, const math::Vec2& To, COLOR Color)
{
	if (m_ActiveNumberC >= m_MaxNumberC) return;	// cannot	

	for (int i=m_NumberI; i<m_MaxNumberC; i++)
	{
		if (!m_NumberA[i].IsValid())
		{
			m_NumberA[i].SetColor(Color);
			FillNumber(&m_NumberA[i], Number, From, To);
			m_NumberI = i;
			m_ActiveNumberC++;
			return;
		}
	}
	for (int i=0; i<m_NumberI; i++)
	{
		if (!m_NumberA[i].IsValid())
		{
			m_NumberA[i].SetColor(Color);
			FillNumber(&m_NumberA[i], Number, From, To);
			m_NumberI = i;
			m_ActiveNumberC++;
			return;
		}
	}
}


void	BackdropNumberFXSet::FillNumber(BackdropNumberFXEntry*	pNum, int Number, const math::Vec2& From, const math::Vec2& To)
{
	num::RAND32&	Rand = num::RAND32::Instance();
	pNum->Reset(Number, m_Number.GetDigitC(Number, true), From, To, m_Time);
	pNum->SetupWave(Rand.RandFloat(m_MoveTime.x, m_MoveTime.y),
					Rand.RandFloat(0, 3.14f * 2.0f),
					Rand.RandFloat(m_MoveAmplitude.x, m_MoveAmplitude.y));
}

void	BackdropNumberFXSet::Setup(const math::Vec2& Time, const math::Vec2& Speed, const math::Vec2& Amplitude, bool Fade)
{
	m_MoveTime			= Time;
	m_MoveSpeed			= Speed;
	m_MoveAmplitude		= Amplitude;
	m_Fade				= Fade;
}